#
import os
from typing import List
from mlxtend.frequent_patterns import fpgrowth
from mlxtend.frequent_patterns import apriori
import xlrd
import logging
import time
from harvesttext import HarvestText
from harvesttext.resources import get_baidu_stopwords
from tqdm import tqdm
import jieba
from gensim import corpora
from gensim.models import LdaModel
from gensim.corpora import Dictionary
from gensim.models import CoherenceModel

ht = HarvestText()

# TODO
# 如果后期要转换为命令行格式，这些都是必填的参数项

xls_folder_path = './wb_jc_0429_0503'  # 存放表格数据的路径, str
xls_column = 7  # 要抽取的文本列, int
frequent_mode = ''  # 选择何种方法进行频繁项集抽取
log_info = 'test'


# 日志信息基础确认
logging.basicConfig(
    level=logging.DEBUG,
    filemode='a',
    filename=f'./log/{time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime())}'
             f'_{xls_column}_{log_info}.log',
    format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'
)


def original_text_load(path) -> List[str]:
    """

    应该是要把多个csv一起读，然后拼凑到一起
    通过文件夹指定时间区间，而这个函数只负责聚合所有文件夹里的文件
    读成一个dataframe是2.0的方案

    但是目前来说，保留其他信息并没用。所以还是输出文档列表比较好。

    # parameter

    path : `str`
        文件夹的路径

    # return

    docs_list : `List[str]`
        文档的列表

    """
    file_list = os.listdir(path)
    file_list = [i for i in file_list if not i.startswith('.')]  # 去除隐藏文件无关项
    docs_list = []

    logging.info(f'开始加载数据 {xls_folder_path}')
    print('开始加载数据\n')
    for xls_file in tqdm(file_list):
        work_book = xlrd.open_workbook(os.path.join(xls_folder_path, xls_file))
        work_sheet = work_book.sheet_by_index(0)  # 默认第一个工作表
        col_data = work_sheet.col_values(xls_column)
        col_data.pop(0)  # 删除表头
        docs_list = docs_list + col_data

    clean_doc_list = []
    logging.info('清洗数据 开始')
    print('开始 清洗数据\n')
    for doc in tqdm(docs_list):
        tmp_text = ht.clean_text(doc).replace('...', '').replace('#', '')
        if len(tmp_text) <= 7:  # 小于七个中文字符直接放弃
            continue
        clean_doc_list.append(tmp_text)

    logging.info(f'全部 doc_length: {len(docs_list)}')
    logging.info(f'有效 doc_length: {len(clean_doc_list)}')
    return clean_doc_list


def keyword_find(docs_list, method='jieba_tfidf') -> List[str]:
    """
    找到关键词，输出为关键词列表，
    但是关键词抽取有不同的方案。

    # parameters

    docs_list : `List[str]`
        文档列表

    method : `str`
        只能是 jieba_tfidf 或者 textrank
        因为目前使用的是harvesttext作为基础
        后续可以加入jiagu或者直接使用jieba

    # return

    keywords_list : `List[list[str]]`
        对应每一个文档的一组关键词

    """
    keywords_list = []

    print('开始提取关键词\n')
    for doc in tqdm(docs_list):
        kws = ht.extract_keywords(text=doc, topK=5, method=method)
        keywords_list.append(kws)

    return keywords_list


def frequent_pattern_find(word_group_list) -> List[List[str]]:
    """
    频繁模式的获取涉及到不同的超参数，需要引入一些新的参数

    # parameter

    word_group_list : `List[List[str]]`
        获得词语组

    # return

    frequent_patterns : `List[List[str]]`
        获得频繁模式

    """


def LDA_topic_find(doc_list, topic_num=20, epoch=50) -> LdaModel:
    """
    LDA 主题分析，这本来是一个比较复杂的问题。
    涉及到多个超参数和一些额外判断的技巧。
    LDA只会弄出主题，但是这个主题到底是什么，是否值得关注，
    都需要你自己判断。

    # parameter

    doc_list : `List[str]`
        文档列表

    topic_num : `int`
        考虑有多少个主题, 最大值
        属于超参数

    epoch : `int`
        训练的轮次
        属于超参数

    # return

    lda_model : gensim.models.LdaModel
        最终训练好的模型

    """

    stop_word = list(get_baidu_stopwords())
    cut_docs = []
    for doc in tqdm(doc_list):  # 首先进行分词
        cut_doc = jieba.lcut(doc)
        cut_doc = [i for i in cut_doc if i not in stop_word]  # 去除停用词
        cut_docs.append(cut_doc)

    dictionary = corpora.Dictionary(cut_docs)
    corpus = [dictionary.doc2bow(doc) for doc in cut_docs]

    coherence_score = []
    # perplexity = []
    model_list = []

    print('开始 寻找最佳主题')
    for num_topic in tqdm(range(2, topic_num, 2)):
        lda_model = LdaModel(corpus=corpus,
                             id2word=dictionary,
                             num_topics=num_topic,
                             passes=epoch)
        model_list.append(lda_model)
        coherence_model = CoherenceModel(model=lda_model,
                                         texts=cut_docs,
                                         dictionary=dictionary,
                                         coherence='c_v')
        coherence_score.append(round(coherence_model.get_coherence(), 3))
        print(f'主题 {num_topic}, 分数为：{coherence_model.get_coherence()}')

    max_score, max_score_index = max(coherence_score), coherence_score.index(max(coherence_score))
    logging.info(f'最大分数：{max_score}, 索引为：{max_score_index}')
    lda_model = model_list[max_score_index]

    topics = lda_model.print_topics(num_words=5)
    for topic in topics:
        print(topic)
        logging.info(topic)

    return lda_model


def doc_topic_find(docs_list: List, lda_model: LdaModel) -> List[str]:
    """
    获取到主题之后，想必是要对每个文档赋予具体的分类。

    # parameter

    docs_list : `List[str]`
        文档列表

    lda_model : `LdaModel`
        主题模型

    # return

    topic_list : `List[str]`

    """


def main():
    """
    主函数
    """

    text_list = original_text_load(xls_folder_path)
    # kws_list = keyword_find(text_list)
    topics = LDA_topic_find(text_list)


if __name__ == '__main__':
    main()
